2023/04/05 更新: 為了避免本文章散落在不同網站,之後統一由部落格更新,再麻煩從部落格查看~
將不同資料物件透過一致的方式取得其中的元素
string與[]string是兩種不同的資料型態,我們需要迭代裡頭全部的元素。
設計一個Iteratorinterface 介面,裡頭.HasNext()用來確認是否還擁有下一個元素,.Next()用來取得元素與把元素 index 往後移。
將string與[]string以IterableString{}、IterableSliceString{}實作Iteratorinterface,PrintAllItems()依賴此 interface 將元素印出。
相關的 code 在Github - go-design-patterns
code 如下:
package main
import "fmt"
type Iterator interface {
HasNext() bool
Next() interface{}
}
type IterableSliceString []string
func (i IterableSliceString) Iterator() Iterator {
return &SliceStringIterator{
original: i,
index: 0,
}
}
type SliceStringIterator struct {
original IterableSliceString
index int
}
func (s *SliceStringIterator) HasNext() bool {
return s.index < len(s.original)
}
func (s *SliceStringIterator) Next() interface{} {
item := s.original[s.index]
s.index++
return item
}
type IterableString string
func (i IterableString) Iterator() Iterator {
return &StringIterator{
original: i,
index: 0,
}
}
type StringIterator struct {
original IterableString
index int
}
func (s *StringIterator) HasNext() bool {
return s.index < len(s.original)
}
func (s *StringIterator) Next() interface{} {
item := string(s.original[s.index])
s.index++
return item
}
func PrintAllItems(iterator Iterator) {
for iterator.HasNext() {
fmt.Println(iterator.Next())
}
}
func main() {
PrintAllItems(IterableSliceString{"a", "b", "c"}.Iterator())
PrintAllItems(IterableString("abcd").Iterator())
}
需注意的是,golang 已經有range關鍵字可以迭代string、map、slice等型態,但 Iterator Pattern 不限定這些型態,而是任意型態只要滿足Iteratorinterface 的實作即可,例如 golang database/sql的.Next()就是以 Iterator Pattern 對 rows 一個一個迭代。